home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2007 December / PCWKCD1207B.iso / Blogowanie poza sfera / Flock 0.9.1.3 stable / flock-0.9.1.3.en-US.win32.exe / flock / components / flockBloggerService.js < prev    next >
Text File  |  2007-10-12  |  36KB  |  1,009 lines

  1. // BEGIN FLOCK GPL
  2. // 
  3. // Copyright Flock Inc. 2005-2007
  4. // http://flock.com
  5. // 
  6. // This file may be used under the terms of of the
  7. // GNU General Public License Version 2 or later (the "GPL"),
  8. // http://www.gnu.org/licenses/gpl.html
  9. // 
  10. // Software distributed under the License is distributed on an "AS IS" basis,
  11. // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. // for the specific language governing rights and limitations under the
  13. // License.
  14. // 
  15. // END FLOCK GPL
  16. //
  17.  
  18. const ENABLE_DEBUG = true; // switch to turn off slow debug code for production
  19. function DEBUG(x) { if (ENABLE_DEBUG) debug("flockBloggerService: "+x+"\n"); }
  20.  
  21. const Cc = Components.classes;
  22. const Ci = Components.interfaces;
  23.  
  24. const BLOGGER_CID = Components.ID('{dec6797b-2155-4a79-9872-30f142074f0d}');
  25. const BLOGGER_CONTRACTID = '@flock.com/people/blogger;1';
  26. const BLOGGER_URL = "http://www.blogger.com/";
  27. const BLOGGER_FAVICON = "http://www.blogger.com/favicon.ico";
  28. const SERVICE_ENABLED_PREF          = "flock.service.blogger.enabled";
  29. const CATEGORY_COMPONENT_NAME       = "Blogger JS Component"
  30. const CATEGORY_ENTRY_NAME           = "blogger"
  31.  
  32. var loader = Cc['@mozilla.org/moz/jssubscript-loader;1'].getService(Ci.mozIJSSubScriptLoader);
  33.  
  34. loader.loadSubScript('chrome://browser/content/utilityOverlay.js');
  35. loader.loadSubScript("chrome://browser/content/flock/blog/atom.js");
  36. loader.loadSubScript("chrome://browser/content/flock/blog/blogBackendLib.js");
  37.  
  38. var gCompTK;
  39. function getCompTK() {
  40.   if (!gCompTK) {
  41.     gCompTK = Components.classes["@flock.com/singleton;1"]
  42.                         .getService(Components.interfaces.flockISingleton)
  43.                         .getSingleton("chrome://browser/content/flock/services/common/load-compTK.js")
  44.                         .wrappedJSObject;
  45.   }
  46.   return gCompTK;
  47. }
  48.  
  49. function flockBLService () {
  50.   var obs = Cc["@mozilla.org/observer-service;1"]
  51.                       .getService(Ci.nsIObserverService);
  52.   obs.addObserver(this, 'xpcom-shutdown', false);
  53.   this.status = Ci.flockIWebService.STATUS_UNKNOWN;
  54.  
  55.   this.acUtils = Cc["@flock.com/account-utils;1"].getService(Ci.flockIAccountUtils);
  56.  
  57.   this.url = BLOGGER_URL;
  58.   this.status = Components.interfaces.flockIWebService.STATUS_UNKNOWN;
  59.  
  60.   this.supportsPostReplace = true;
  61.   this.mIsInitialized = false;
  62.  
  63.   this._ctk = {
  64.     interfaces: [
  65.       "nsISupports",
  66.       "nsIClassInfo",
  67.       "nsIObserver",
  68.       "nsISupportsCString",
  69.       "flockIWebService",
  70.       "flockIAuthenticateNewAccount",
  71.       "flockIManageableWebService",
  72.       "flockIBlogWebService"
  73.     ],
  74.     shortName: "blogger",
  75.     fullName: "Blogger",
  76.     description: "Google's Blogger.com Web Service",
  77.     favicon: BLOGGER_FAVICON,
  78.     CID: BLOGGER_CID,
  79.     contractID: BLOGGER_CONTRACTID,
  80.     accountClass: flockBLAccount
  81.   };
  82.   this._profiler = Cc["@flock.com/profiler;1"].getService(Ci.flockIProfiler);
  83.  
  84.   this.init();
  85. }
  86.  
  87. // Helpers
  88.  
  89. // For Google Auth (ClientLogin)
  90. flockBLService.prototype._parseError =
  91. function (aErrorString) {
  92.   var result = {};
  93.   var lines = aErrorString.split('\n');
  94.   for (i in lines) {
  95.     if (lines[i].length > 0) {
  96.       entry = lines[i].split('=');
  97.       result[entry[0]] = entry[1];
  98.     }
  99.   }
  100.  
  101.   return result;
  102. }
  103.  
  104.  
  105. // nsIObserver
  106. flockBLService.prototype.observe = function flockBLService_observe(subject, topic, state) {
  107.   switch (topic) {
  108.     case 'xpcom-shutdown':
  109.       var obs = Cc["@mozilla.org/observer-service;1"]
  110.         .getService(Ci.nsIObserverService);
  111.       obs.removeObserver(this, 'xpcom-shutdown');
  112.       return;
  113.   }
  114. }
  115.  
  116. // flockIWebService implementation
  117. flockBLService.prototype.addAccount =
  118. function flockBGService_addAccount(aUsername, aPassword, aListener)
  119. {
  120.   //DEBUG("{flockIWebService}.addAccount('"+aUsername+"', 'XXXXXXXX', ...)");
  121.   //DEBUG(" THIS FUNCTION IS DEPRECATED AND SHOULD BE REPLACED WITH A CALL TO addAccountById() !");
  122.   return this.addAccountById(aUsername, true, aListener);
  123. }
  124.  
  125. flockBLService.prototype.addAccountById =
  126. function flockBLService_addAccountById(aUsername, aIsTransient, aListener)
  127. {
  128.   var accountURN = this.urn+":"+aUsername;
  129.   var account = new this.faves_coop.Account(accountURN, {
  130.     name: aUsername,
  131.     serviceId: this.contractId,
  132.     service: this.blService,
  133.     accountId: aUsername,
  134.     favicon: this.icon,
  135.     URL: this.url,
  136.     isPollable: false,
  137.     isTransient: aIsTransient,
  138.     showInSidebar: false
  139.   });
  140.   this.faves_coop.accounts_root.children.addOnce(account);
  141.   // this.USER = blAccount.id();
  142.   // var acct = this.getAccount(blAccount.id());
  143.  
  144.   // Add the notification stream
  145.   var notificationStream = new this.faves_coop.Stream(accountURN + ":notifications", {
  146.     name: "Notification",
  147.     isPollable: false,
  148.     isIndexable: false,
  149.     notify: true,
  150.     serviceId: this.contractId
  151.   });
  152.   account.children.addOnce(notificationStream);
  153.  
  154.   this.USER = accountURN;
  155.   var acct;
  156.  
  157.   // Add the blog account
  158.   blsvc = this;
  159.   var listener = {
  160.     onResult: function(aResult) {
  161.       var theBlog;
  162.       while (aResult.hasMoreElements()) {
  163.         theBlog = aResult.getNext();
  164.         theBlog.QueryInterface(Ci.flockIBlogAccount);
  165.         theCoopBlog = new blsvc.faves_coop.Blog(accountURN+":"+theBlog.title, {
  166.           name: theBlog.title,
  167.           title: theBlog.title,
  168.           blogid: theBlog.blogid,
  169.           URL: theBlog.URL,
  170.           apiLink: theBlog.apiLink,
  171.           authtoken: theBlog.authtoken
  172.         });
  173.         account.children.addOnce(theCoopBlog);
  174.       }
  175.       if (aListener) aListener.onSuccess(acct, "addAccount");
  176.     },
  177.     onFault: function(aError) {
  178.       notificationStream.destroy();
  179.       blsvc.faves_coop.accounts_root.children.remove(account);
  180.       account.destroy();
  181.       if (aListener) {
  182.         var error = Components.classes['@flock.com/error;1'].createInstance(Components.interfaces.flockIError);
  183.         error.serviceErrorString = aError;
  184.         aListener.onError(null, 'FAULT', error);
  185.       }
  186.     },
  187.     onError: function(aError) {
  188.       notificationStream.destroy();
  189.       blsvc.faves_coop.accounts_root.children.remove(account);
  190.       account.destroy();
  191.       if(aListener) {
  192.         aListener.onError(null, 'ERROR', aError);
  193.       }
  194.     }
  195.   }
  196.  
  197.   if (aUsername.match('@'))
  198.     this.getUsersBlogs(listener, 'http://beta.blogger.com/feeds/default/blogs');
  199.   else
  200.     this.getUsersBlogs(listener, 'http://www.blogger.com/feeds/default/blogs');
  201.  
  202.   acct = this.getAccount(accountURN);
  203.   return acct;
  204. }
  205.  
  206.  
  207. flockBLService.prototype.init =
  208. function ()
  209. {
  210.   DEBUG(".init()");
  211.  
  212.   // Prevent re-entry
  213.   if (this.mIsInitialized) return;
  214.   this.mIsInitialized = true;
  215.  
  216.   var evtID = this._profiler.profileEventStart("blogger-init");
  217.  
  218.   this.prefService = Components.classes["@mozilla.org/preferences-service;1"]
  219.                                .getService(Components.interfaces.nsIPrefBranch);
  220.   if ( this.prefService.getPrefType(SERVICE_ENABLED_PREF) &&
  221.        !this.prefService.getBoolPref(SERVICE_ENABLED_PREF) )
  222.   {
  223.     DEBUG("Pref "+SERVICE_ENABLED_PREF+" set to FALSE... not initializing.");
  224.     var catMgr = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
  225.     catMgr.deleteCategoryEntry("wsm-startup", CATEGORY_COMPONENT_NAME, true);
  226.     catMgr.deleteCategoryEntry("flockWebService", CATEGORY_ENTRY_NAME, true);
  227.     return;
  228.   }
  229.  
  230.   this.acUtils = Cc["@flock.com/account-utils;1"].getService(Ci.flockIAccountUtils);
  231.  
  232.   this.logger = Cc['@flock.com/logger;1'].createInstance(Ci.flockILogger);
  233.   this.logger.init("blogger");
  234.  
  235.   this.faves_coop = Cc['@flock.com/singleton;1'].getService(Ci.flockISingleton).getSingleton('chrome://browser/content/flock/common/load-faves-coop.js').wrappedJSObject;
  236.  
  237.   this.blService = new this.faves_coop.Service('urn:blogger:service');
  238.   this.blService.name = 'blogger';
  239.   this.blService.desc = 'The Blogger.com Service';
  240.   this.blService.logoutOption = false;
  241.   this.blService.domains = "google.com,blogger.com";
  242.   this.blService.serviceId = BLOGGER_CONTRACTID;
  243.  
  244.   this.urn = this.blService.id();
  245.   this.webDetective = this.acUtils.useWebDetective("blogger.xml");
  246.  
  247.   this._profiler.profileEventEnd(evtID, "");
  248. }
  249.  
  250.  
  251. flockBLService.prototype.refresh =
  252. function (aURN, aListener) {
  253.   throw Components.results.NS_ERROR_ABORT;
  254. }
  255.  
  256.  
  257. // BEGIN flockIBlogWebService interface
  258.  
  259. function atomListener(aListener){
  260.   this.listener = aListener;
  261.   this.logger = Cc['@flock.com/logger;1']
  262.     .getService(Ci.flockILogger);
  263.   this.logger.init("blog");
  264. }
  265.  
  266. atomListener.prototype = {
  267.   onResult: function(aResult) {
  268.     this.listener.onResult(aResult.atomid);
  269.   },
  270.   onError: function(error) {
  271.     this.logger.error("<<<<<<<<<< Google API: SERVER TO FLOCK");
  272.     this.logger.error("ERROR "+error);
  273.     this.listener.onError(error);
  274.   },
  275.   onFault: function(error) {
  276.     this.logger.error("<<<<<<<<<< Google API: SERVER TO FLOCK");
  277.     this.logger.error("FAULTAA "+error);
  278.     this.listener.onFault(error);
  279.   }
  280. }
  281.  
  282. flockBLService.prototype.doAuthRequest = function(listener, method, url, body, processor) {
  283.   var inst = this;
  284.   this._req = Cc['@mozilla.org/xmlextras/xmlhttprequest;1'].createInstance(Ci.nsIXMLHttpRequest);
  285.   this._req.onreadystatechange = function (aEvt) {
  286.     inst.logger.info("<<<<<<<<<< Google API: SERVER TO FLOCK");
  287.     inst.logger.info("Request readyState: "+inst._req.readyState);
  288.     if(inst._req.readyState == 4) {
  289.       inst.logger.info("Request status: "+inst._req.status);
  290.       inst.logger.debug("\nRESPONSE\n" + inst._req.responseText);
  291.       try {
  292.         if(inst._req.status == 200 || inst._req.status == 201 || inst._req.status == 205) {
  293.         try {
  294.             processor(listener, inst);
  295.           }
  296.           catch(e) {
  297.             // listener.onError(inst.ERROR_PARSER);
  298.             inst.logger.error(e + " " + e.lineNumber);
  299.           }
  300.         }
  301.         else {
  302.           var faultString; //: "Make sure that are not trying to blog really weird html, and note the following kind user:\n\n",
  303.           // };
  304.           // faultString = inst._req.responseText;
  305.           inst.logger.error("Error: "+inst._req.responseText);
  306.           // listener.onFault(faultString);
  307.           var answer = inst._parseError(inst._req.responseText);
  308.           var error = Cc['@flock.com/error;1'].createInstance(Ci.flockIError);
  309.           error.serviceErrorString = answer["Error"];
  310.           inst.logger.error("***"+error.serviceErrorString+"***");
  311.           switch (error.serviceErrorString) {
  312.             case "BadAuthentication": // Invalid login/pass
  313.               error.errorCode = Ci.flockIError.BLOG_INVALID_AUTH;
  314.               error.errorString = "Bad authentication";
  315.               break;
  316.             case "CaptchaRequired":
  317.               error.errorCode = Ci.flockIError.BLOG_CAPTCHA_REQUIRED;
  318.               error.errorString = "Captcha Required";
  319.               break;
  320.              case "NotVerified":
  321.               error.errorCode = Ci.flockIError.BLOG_NOT_VERIFIED;
  322.               error.errorString = "Email Not Verified";
  323.               break;           
  324.             default: // Unknown error code
  325.               error.errorCode = Ci.flockIError.BLOG_UNKNOWN;
  326.               error.errorString = "Unknown Error";
  327.           }
  328.           listener.onError(error);
  329.         }
  330.       } catch(e) {
  331.         inst.logger.error(e + " " + e.fileName + " " + e.lineNumber);
  332.         listener.onError(inst.ERROR_PARSER);
  333.       }
  334.     }
  335.   };
  336.   rval = this._req.open(method, url, true);
  337.   this._req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  338.   this.logger.info(">>>>>>>>>> Google API: FLOCK TO SERVER");
  339.   this.logger.info("\nSENDING\n" + body);
  340.   this.logger.info("\nTO\n" + method + " @ " + url);
  341.   rval = this._req.send(body);
  342. }
  343.  
  344. flockBLService.prototype.doRequest = function(listener, method, url, body, authToken, processor) {
  345.   var inst = this;
  346.   this._req = Cc['@mozilla.org/xmlextras/xmlhttprequest;1'].createInstance(Ci.nsIXMLHttpRequest);
  347.   this._req.onreadystatechange = function (aEvt) {
  348.     inst.logger.info("<<<<<<<<<< Google API: SERVER TO FLOCK");
  349.     debug("<<<<<<<<<< Google API: SERVER TO FLOCK\n");
  350.     inst.logger.info("Request readyState: "+inst._req.readyState);
  351.     debug("Request readyState: "+inst._req.readyState+"\n");
  352.     if (inst._req.readyState == 4) {
  353. //      inst.logger.info("Request status: "+inst._req.status);
  354. //      debug("Request status: "+inst._req.status+"\n");
  355.       inst.logger.info("\nRESPONSE\n" + inst._req.responseText);
  356.       debug("\nRESPONSE\n" + inst._req.responseText+"\n");
  357.       try {
  358.         if (inst._req.status == 200 || inst._req.status == 201 || inst._req.status == 205) {
  359.           try {
  360.             processor(listener, inst, authToken);
  361.           }
  362.           catch(e) {
  363.             // listener.onError(inst.ERROR_PARSER);
  364.             inst.logger.error(e + " " + e.lineNumber);
  365.           }
  366.         }
  367.         else {
  368.           var faultString; //: "Make sure that are not trying to blog really weird html, and note the following kind user:\n\n",
  369.           faultString = inst._req.responseText;
  370.           inst.logger.error(faultString+"\n");
  371.           listener.onFault(faultString);
  372.         }
  373.       } catch(e) {
  374.         inst.logger.error(e + " " + e.fileName + " " + e.lineNumber);
  375.         listener.onError(inst.ERROR_PARSER);
  376.       }
  377.     }
  378.   };
  379.   rval = this._req.open(method, url, true);
  380.   this._req.setRequestHeader("Authorization", "GoogleLogin auth="+authToken);
  381.   this.logger.info(">>>>>>>>>> Google API: FLOCK TO SERVER");
  382.   debug(">>>>>>>>>> Google API: FLOCK TO SERVER\n");
  383.   this.logger.info("\nSENDING\n" + body);
  384.   debug("\nSENDING\n" + body+"\n");
  385.   this.logger.info("\nTO\n" + method + " @ " + url);
  386.   debug("\nTO\n" + method + " @ " + url+"\n");
  387.   rval = this._req.send(body);
  388. }
  389.  
  390. flockBLService.prototype.parseUsersBlogs = function(listener, inst, authToken) {
  391.   try {
  392.     var result = new Array();
  393.     var dom = inst._req.responseXML;
  394.  
  395.     var domEntries = dom.getElementsByTagName("entry");
  396.     for (i=0; i<domEntries.length; i++) {
  397.       domEntry = domEntries[i];
  398.       title = domEntry.getElementsByTagName("title")[0].textContent;
  399.       var newAccount = new BlogAccount(title);
  400.       newAccount.api = this.shortName;
  401.       newAccount.authtoken = authToken;
  402.       var links = domEntry.getElementsByTagName("link");
  403.       for (j=0; j<links.length; j++) {
  404.         var link = links[j]
  405.         switch (link.getAttribute("rel")) {
  406.           case "alternate":
  407.             newAccount.URL = link.getAttribute("href");
  408.             break;
  409.           case "http://schemas.google.com/g/2005#post":
  410.             newAccount.apiLink = link.getAttribute("href");
  411.             break;
  412.         }
  413.       }
  414.       result.push(newAccount);
  415.     }
  416.     debug("Found "+ result.length +" blogs\n");
  417.     listener.onResult(new simpleEnumerator(result));
  418.   }
  419.   catch(e) {
  420.     var logger = Cc['@flock.com/logger;1']
  421.        .getService(Ci.flockILogger);
  422.     logger.init("blog");
  423.     logger.error(e + " " + e.lineNumber);
  424.     listener.onError(e + " " + e.lineNumber);
  425.   }
  426. }
  427.  
  428. flockBLService.prototype.parseRecentPosts = function(listener, inst) {
  429.   var getNamedChild = function(node, name) {
  430.     for(var i=0;i<node.childNodes.length;++i) {
  431.       if(node.childNodes[i].nodeName==name)
  432.         return node.childNodes[i];
  433.     }
  434.     return null;
  435.   };
  436.  
  437.   var result = new Array();
  438.  
  439.   debug(inst._req.responseText);
  440.  
  441.   var dom = inst._req.responseXML;
  442.   var entries = dom.getElementsByTagName("entry");
  443.   for(var i=0;i<entries.length;++i) {
  444.     try {
  445.       var entry_n = entries[i];
  446.       var post = new BlogPost();
  447.       post.title = getNamedChild(entry_n, "title").firstChild.nodeValue;
  448.       post.issued = getNamedChild(entry_n, "published").firstChild.nodeValue;
  449.  
  450.       var atomid_n = entry_n.getElementsByTagName("id")[0];
  451.       post.postid = "";
  452.       if(atomid_n) post.postid = atomid_n.firstChild.nodeValue; //.split('/').pop();
  453.  
  454.       var link_n = null;
  455.       for(var j=0;j<entry_n.childNodes.length;++j) {
  456.         if(entry_n.childNodes[j].nodeName=="link") {
  457.           var tmp = entry_n.childNodes[j];
  458.           if(tmp.getAttribute("rel").match(/edit/)) {
  459.             link_n = tmp;
  460.           }
  461.           if(tmp.getAttribute("rel").match(/alternate/)) {
  462.             permalink_n = tmp;
  463.           }
  464.         }
  465.       }
  466.  
  467.       var permaLink = permalink_n.getAttribute("href");
  468.       var href = link_n.getAttribute("href");
  469.       // href.match(/.+\/(.+)/);
  470.       post.editURI = href; // RegExp.$1;
  471.       debug("post.editURI: "+post.editURI+"\n");
  472.  
  473.       result.push(post);
  474.     }
  475.     catch(e) {
  476.       var logger = Cc['@flock.com/logger;1']
  477.         .getService(Ci.flockILogger);
  478.       logger.error(e + " " + e.lineNumber + " " + e.fileName);
  479.     }
  480.   }
  481.   listener.onResult(new simpleEnumerator(result));
  482. }
  483.  
  484. flockBLService.prototype.newPost =
  485. function(aListener, aBlogId, aPost, aPublish, aNotifications)
  486. {
  487.   var svc = this;
  488.   var gBlogService = Cc['@flock.com/flock-blog;1'].getService(Ci['flockIBlogService']);
  489.   var account = gBlogService.getAccount(aBlogId);
  490.  
  491.   var listener = {
  492.     onResult: function(aResult) {
  493.       aListener.onResult(aResult.atomid);
  494.     },
  495.     onError: function(error) {
  496.       svc.logger.error("<<<<<<<<<< Google API: SERVER TO FLOCK");
  497.       svc.logger.error("ERROR " + error.serviceErrorString);
  498.       aListener.onError(error);
  499.     },
  500.     onFault: function(error) {
  501.       svc.logger.error("<<<<<<<<<< Google API: SERVER TO FLOCK");
  502.       svc.logger.error("FAULTXX "+error.serviceErrorString);
  503.       if (error.serviceErrorCode == 401) {
  504.         // The token is bad or missing, let's get a brand new one
  505.         var parseAuthToken = function (listener, inst){
  506.           var response = inst._req.responseText;
  507.           response.match(/Auth=(.+)/);
  508.           var token = RegExp.$1;
  509.           var coopBlog = svc.faves_coop.get(aBlogId);
  510.           coopBlog.authtoken = token;
  511.           svc.newPost(aListener, aBlogId, aPost, aPublish, aNotifications);
  512.         };
  513.         var body = 'Email='+encodeURIComponent(account.username)+'&Passwd='+encodeURIComponent(account.password)+'&service=blogger&source=FlockInc-Flock-0.8';
  514.         svc.doAuthRequest(listener, "POST", "https://www.google.com/accounts/ClientLogin", body, parseAuthToken);
  515.       }
  516.       else
  517.         aListener.onFault(error);
  518.     }
  519.   }
  520.  
  521.   var atomEntry = {
  522.     title: aPost.title,
  523.     content: aPost.description
  524.   };
  525.   var labels = new Array();
  526.   if (aPost.tags)
  527.     while (aPost.tags.hasMore()) {
  528.       var label = aPost.tags.getNext();
  529.       if (label.length > 0)
  530.         labels.push(label);
  531.     }
  532.   if (labels.length > 0)
  533.     atomEntry.categories = labels;
  534.   // Hack because Blogger announce www but takes beta
  535.   var url = account.apiLink.replace('www', 'beta');
  536.   flockAtomPost (listener, url, atomEntry, account.authtoken);
  537. }
  538.  
  539. flockBLService.prototype.editPost =
  540. function(aListener, aBlogId, aPost, aPublish, aNotifications)
  541. {
  542.   var gBlogService = Cc['@flock.com/flock-blog;1'].getService(Ci['flockIBlogService']);
  543.   var account = gBlogService.getAccount(aBlogId);
  544.  
  545.   if (account.username.match('@')) { // Blogger beta
  546.     var listener = new atomListener(aListener);
  547.     var account = gBlogService.getAccount(aBlogId);
  548.  
  549.     var atomEntry = {
  550.       id: aPost.postid,
  551.       title: aPost.title,
  552.       content: aPost.description,
  553.       issued: aPost.issued
  554.     };
  555.     var labels = new Array();
  556.     while (aPost.tags.hasMore())
  557.       labels.push(aPost.tags.getNext());
  558.     if (labels.length > 0)
  559.       atomEntry.categories = labels;
  560.     // Hack because Blogger announce www but takes beta
  561.     var url = aPost.editURI.replace('www', 'beta');
  562.     flockAtomEdit (listener, url, atomEntry, account.authtoken);
  563.   }
  564.   else {
  565.     var atomAPI = Cc['@flock.com/blog/service/atom;1'].getService (Ci.flockIBlogWebService);
  566.     atomAPI.editPost(aListener, aBlogId, aPost, aPublish, aNotifications);
  567.   }
  568. }
  569.  
  570. flockBLService.prototype.deletePost =
  571. function(aListener, aBlogId, aPostid)
  572. {
  573.   var gBlogService = Cc['@flock.com/flock-blog;1'].getService(Ci['flockIBlogService']);
  574.   var account = gBlogService.getAccount(aBlogId);
  575.  
  576.   if (account.username.match('@')) { // Blogger beta
  577.     var handleDelete = function(listener, inst) {
  578.       listener.onResult(1);
  579.     }
  580.  
  581.     var gBlogService = Cc['@flock.com/flock-blog;1'].getService(Ci['flockIBlogService']);
  582.     var account = gBlogService.getAccount(aBlogId);
  583.     var url = account.apiLink;
  584.     url += "/" + aPostid;
  585.     // if(aEditURI) url = aEditURI;
  586.     this.doRequest(aListener,"DELETE", url, null, account.authtoken, handleDelete);
  587.   }
  588.   else {
  589.     var atomAPI = Cc['@flock.com/blog/service/atom;1'].getService (Ci.flockIBlogWebService);
  590.     atomAPI.deletePost(aListener, aBlogId, aPostid);
  591.   }
  592. }
  593.  
  594.  
  595. flockBLService.prototype._getUsersBlogs =
  596. function(aListener, aAPILink)
  597. {
  598.   var inst = this;
  599.   this._req = Cc['@mozilla.org/xmlextras/xmlhttprequest;1'].createInstance(Ci.nsIXMLHttpRequest);
  600.   this._req.onreadystatechange = function (aEvt) {
  601.     inst.logger.info("<<<<<<<<<< Blogger: SERVER TO FLOCK");
  602.     inst.logger.info("Request readyState: "+inst._req.readyState);
  603.     if(inst._req.readyState == 4) {
  604.       inst.logger.info("Request status: "+inst._req.status);
  605.       inst.logger.info("\nRESPONSE\n" + inst._req.responseText);
  606.       //try {
  607.         if(inst._req.status == 200 || inst._req.status == 201 || inst._req.status == 205) {
  608.         //try {
  609.           var result = new Array();
  610.           var dom = inst._req.responseXML;
  611.  
  612.           if (!dom) {
  613.             debug("Problem: "+inst._req.responseText+"\n");
  614.             listener.onError(null);
  615.           }
  616.  
  617.           var domEntries = dom.getElementsByTagName("entry");
  618.           for (i=0; i<domEntries.length; i++) {
  619.             domEntry = domEntries[i];
  620.             title = domEntry.getElementsByTagName("title")[0].textContent;
  621.             var newAccount = new BlogAccount(title);
  622.             newAccount.api = this.shortName;
  623.             var links = domEntry.getElementsByTagName("link");
  624.             for (j=0; j<links.length; j++) {
  625.               var link = links[j]
  626.               switch (link.getAttribute("rel")) {
  627.                 case "alternate":
  628.                   newAccount.URL = link.getAttribute("href");
  629.                   break;
  630.                 case "http://schemas.google.com/g/2005#post":
  631.                   newAccount.apiLink = link.getAttribute("href");
  632.                   break;
  633.               }
  634.             }
  635.             result.push(newAccount);
  636.           }
  637.           debug("Found "+ result.length +" blogs\n");
  638.           aListener.onResult(new simpleEnumerator(result));
  639.         //}
  640.         //catch(e) {
  641.           // listener.onError(inst.ERROR_PARSER);
  642.           //inst.logger.error(e + " " + e.lineNumber+"\n");
  643.         //}
  644.       }
  645.       else {
  646.         var faultString; //: "Make sure that are not trying to blog really weird html, and note the following kind user:\n\n",
  647.         faultString = inst._req.responseText;
  648.         //faultString += inst._req;
  649.         inst.logger.error(faultString);
  650.         aListener.onFault(faultString);
  651.       }
  652.     //} catch(e) {
  653.     //  inst.logger.error(e + " " + e.fileName + " " + e.lineNumber + "\n");
  654.     //  listener.onError(inst.ERROR_PARSER);
  655.     //  }
  656.     }
  657.   };
  658.  
  659.   var username = this.faves_coop.get(this.USER).name;
  660.   debug("USER: "+username+"\n");
  661.   var pw = this.acUtils.getPassword(this.urn+':'+username);
  662.  
  663.   rval = this._req.open("GET", aAPILink, true, username, pw.password);
  664.   rval = this._req.send(null);
  665. }
  666.  
  667. flockBLService.prototype._getUsersBlogsBeta = function (aListener, aUrl){
  668.   debug("getUsersBlog... "+aUrl+"\n");
  669.   var inst = this;
  670.  
  671.   var parseAuthToken = function (listener, inst){
  672.     var response = inst._req.responseText;
  673.     response.match(/Auth=(.+)/);
  674.     var token = RegExp.$1;
  675.     debug("Found the token: "+token+"\n");
  676.     listener.onResult(token);
  677.   };
  678.  
  679.   var listener = {
  680.     onResult: function(aToken) {
  681.       inst.doRequest(aListener, "GET", aUrl, null, aToken, inst.parseUsersBlogs);
  682.     },
  683.     onError: function(aError) {
  684.       aListener.onError(aError);
  685.     },
  686.     onFault: function(aError) {
  687.       aListener.onError(aError);
  688.     }
  689.   }
  690.  
  691.   var username = this.faves_coop.get(this.USER).name;
  692.   debug("USER: "+username+"\n");
  693.   var pw = this.acUtils.getPassword(this.urn+':'+username);
  694.  
  695.   var body = 'Email='+encodeURIComponent(username)+'&Passwd='+encodeURIComponent(pw.password)+'&service=blogger&source=FlockInc-Flock-0.8';
  696.   this.doAuthRequest(listener, "POST", "https://www.google.com/accounts/ClientLogin", body, parseAuthToken);
  697. }
  698.  
  699. flockBLService.prototype.getUsersBlogs =
  700. function(aListener, aAPILink)
  701. {
  702.   var username = this.faves_coop.get(this.USER).name;
  703.   if (username.match('@'))
  704.     this._getUsersBlogsBeta(aListener, aAPILink);
  705.   else
  706.     this._getUsersBlogs(aListener, aAPILink);
  707. }
  708.  
  709. flockBLService.prototype.getRecentPosts = function(aListener, aBlogId, aNumber){
  710.   var gBlogService = Cc['@flock.com/flock-blog;1'].getService(Ci['flockIBlogService']);
  711.   var account = gBlogService.getAccount(aBlogId);
  712.  
  713.   var url = account.apiLink;
  714.   url.match(/(.+\/)(.+)/);
  715.   if (RegExp.$2 == "post") {
  716.     url = RegExp.$1 + "feed";
  717.   }
  718.   
  719.   var listener = {
  720.     onResult: function(aResult) {
  721.       aListener.onResult(aResult);
  722.     },
  723.     onError: function(error) {
  724.       svc.logger.error("<<<<<<<<<< Google API: SERVER TO FLOCK");
  725.       svc.logger.error("ERROR " + error.serviceErrorString);
  726.       aListener.onError(error);
  727.     },
  728.     onFault: function(error) {
  729.       svc.logger.error("<<<<<<<<<< Google API: SERVER TO FLOCK");
  730.       svc.logger.error("FAULTXX "+error.serviceErrorString);
  731.       if (error.serviceErrorCode == 401) {
  732.         // The token is bad or missing, let's get a brand new one
  733.         var parseAuthToken = function (listener, inst){
  734.           var response = inst._req.responseText;
  735.           response.match(/Auth=(.+)/);
  736.           var token = RegExp.$1;
  737.           var coopBlog = svc.faves_coop.get(aBlogId);
  738.           coopBlog.authtoken = token;
  739.           inst.doRequest(listener, "GET", url, null, token, inst.parseRecentPosts);
  740.         };
  741.         var body = 'Email='+encodeURIComponent(account.username)+'&Passwd='+encodeURIComponent(account.password)+'&service=blogger&source=FlockInc-Flock-0.8';
  742.         inst.doAuthRequest(listener, "POST", "https://www.google.com/accounts/ClientLogin", body, parseAuthToken);
  743.       }
  744.       else
  745.         aListener.onFault(error);
  746.     }
  747.   }
  748.   
  749.   this.doRequest(listener, "GET", url, null, account.authtoken, this.parseRecentPosts);
  750. }
  751.  
  752. flockBLService.prototype.getCategoryList = function(aListener, aBlogId){
  753.   aListener.onResult(null);
  754. }
  755.  
  756. // END flockIBlogWebService interface
  757.  
  758.  
  759. // BEGIN flockIManageableWebService interface
  760. flockBLService.prototype.docRepresentsSuccessfulLogin =
  761. function flockBLService_docRepresentsSuccessfulLogin(aDocument)
  762. {
  763.   this.logger.debug("{flockIManageableWebService}.docRepresentsSuccessfulLogin(aDocument)");
  764.   aDocument.QueryInterface(Components.interfaces.nsIDOMHTMLDocument);
  765.   return this.webDetective.detect("blogger", "loggedin", aDocument, null);
  766. }
  767.  
  768. flockBLService.prototype.ownsDocument =
  769. function flockBLService_ownsDocument(aDocument)
  770. {
  771.   this.logger.debug("{flockIManageableWebService}.ownsDocument(aDocument)");
  772.   aDocument.QueryInterface(Components.interfaces.nsIDOMHTMLDocument);
  773.   var ios = Components.classes["@mozilla.org/network/io-service;1"]
  774.                       .getService(Components.interfaces.nsIIOService);
  775.   var uri = ios.newURI(aDocument.URL, null, null);
  776.   if ((uri.host == "blogger.com") || (uri.host.indexOf(".blogger.com") > 0)) {
  777.     return true;
  778.   }
  779.   if (uri.host.indexOf("google.com") > -1) {// Login page for Blogger Beta
  780.     return true;
  781.   }
  782.   return false;
  783. }
  784.  
  785. flockBLService.prototype.updateAccountStatusFromDocument =
  786. function flockBLService_updateAccountStatusFromDocument(aDocument)
  787. {
  788.   this.logger.debug("{flockIManageableWebService}.updateAccountStatusFromDocument(aDocument)");
  789.   if (this.ownsDocument(aDocument)) {
  790.     if (this.docRepresentsSuccessfulLogin(aDocument)) {
  791.       var accountID = this.getAccountIDFromDocument(aDocument);
  792.       
  793.       var results = Components.classes["@mozilla.org/hash-property-bag;1"].createInstance(Components.interfaces.nsIWritablePropertyBag2);
  794.  
  795.       var avatarURL;
  796.       if(this.webDetective.detect("blogger", "accountinfo", aDocument, results)) {
  797.         try {
  798.           avatarURL = results.getPropertyAsAString("avatarURL");
  799.         } catch(e) {
  800.           // No avatar found
  801.         }
  802.       }
  803.  
  804.       var acctURN = this.acUtils.getAccountURNById(this.urn, accountID);
  805.       var acct = this.faves_coop.get(acctURN);
  806.       if (acct) {
  807.         acct.avatar = avatarURL;
  808.  
  809.         var accounts = this.faves_coop.Account.find({serviceId: BLOGGER_CONTRACTID});
  810.         for (var i = 0; i < accounts.length; i++) {
  811.           if (accounts[i].id() == acctURN) {
  812.             accounts[i].isAuthenticated = true;
  813.           } else {
  814.             accounts[i].isAuthenticated = false;
  815.           }
  816.         }
  817.       }
  818.     } else {
  819.       var login = aDocument.getElementById("Login");
  820.       if (login) {
  821.         this.acUtils.markAllAccountsAsLoggedOut(BLOGGER_CONTRACTID);
  822.       }
  823.     }
  824.   }
  825. }
  826.  
  827. flockBLService.prototype.logout = function() {
  828.   this.logger.info("{flockIWebServiceService}.logout()");
  829.   var cookieManager = Components.classes["@mozilla.org/cookiemanager;1"]
  830.                                 .getService(Components.interfaces.nsICookieManager);
  831.   cookieManager.remove(".blogger.com", "blogger_SID", "/", false);
  832.   cookieManager.remove(".blogger.com", "B2I", "/", false);
  833.   cookieManager.remove(".blogger.com", "ServerID", "/", false);
  834.   cookieManager.remove(".blogger.com", "S", "/", false);
  835.   cookieManager.remove(".blogger.com", "__utma", "/", false);
  836.   cookieManager.remove(".blogger.com", "__utmb", "/", false);
  837.   cookieManager.remove(".blogger.com", "__utmc", "/", false);
  838.   cookieManager.remove(".blogger.com", "__utmz", "/", false);
  839.   cookieManager.remove(".blogger.com", "NSC_cmphhfs-fyu", "/", false);
  840.   cookieManager.remove("blogger.com", "NSC_cmphhfs-fyu", "/", false);
  841.   cookieManager.remove("www.blogger.com", "NSC_cmphhfs-fyu", "/", false);
  842.   cookieManager.remove("www.blogger.com", "JSESSIONID", "/", false);
  843.   cookieManager.remove(".www2.blogger.com", "__utma", "/", false);
  844.   cookieManager.remove(".www2.blogger.com", "__utmb", "/", false);
  845.   cookieManager.remove(".www2.blogger.com", "__utmc", "/", false);
  846.   cookieManager.remove(".www2.blogger.com", "__utmz", "/", false);
  847.   cookieManager.remove("www2.blogger.com", "S", "/", false);
  848.   cookieManager.remove("www.google.com", "LSID", "/accounts", false);
  849. }
  850.  
  851.  
  852. // END flockIManageableWebService interface
  853.  
  854.  
  855.  
  856. // ================================================
  857. // ========== BEGIN XPCOM Module support ==========
  858. // ================================================
  859.  
  860. function createModule(aParams) {
  861.   var Cc = Components.classes;
  862.   var Ci = Components.interfaces;
  863.   var Cr = Components.results;
  864.   return {
  865.     registerSelf: function (aCompMgr, aFileSpec, aLocation, aType) {
  866.       aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
  867.       aCompMgr.registerFactoryLocation( aParams.CID, aParams.componentName,
  868.                                         aParams.contractID, aFileSpec,
  869.                                         aLocation, aType );
  870.       var catMgr = Cc["@mozilla.org/categorymanager;1"]
  871.         .getService(Ci.nsICategoryManager);
  872.       if (!aParams.categories) { aParams.categories = []; }
  873.       for (var i = 0; i < aParams.categories.length; i++) {
  874.         var cat = aParams.categories[i];
  875.         catMgr.addCategoryEntry( cat.category, cat.entry,
  876.                                  cat.value, true, true );
  877.       }
  878.     },
  879.     getClassObject: function (aCompMgr, aCID, aIID) {
  880.       if (!aCID.equals(aParams.CID)) { throw Cr.NS_ERROR_NO_INTERFACE; }
  881.       if (!aIID.equals(Ci.nsIFactory)) { throw Cr.NS_ERROR_NOT_IMPLEMENTED; }
  882.       return { // Factory
  883.         createInstance: function (aOuter, aIID) {
  884.           if (aOuter != null) { throw Cr.NS_ERROR_NO_AGGREGATION; }
  885.           var comp = new aParams.componentClass();
  886.           if (aParams.implementationFunc) { aParams.implementationFunc(comp); }
  887.           return comp.QueryInterface(aIID);
  888.         }
  889.       };
  890.     },
  891.     canUnload: function (aCompMgr) { return true; }
  892.   };
  893. }
  894.  
  895. // NS Module entrypoint
  896. function NSGetModule(aCompMgr, aFileSpec) {
  897.   return createModule({
  898.     componentClass: flockBLService,
  899.     CID: BLOGGER_CID,
  900.     contractID: BLOGGER_CONTRACTID,
  901.     componentName: CATEGORY_COMPONENT_NAME,
  902.     implementationFunc: function (aComp) { getCompTK().addAllInterfaces(aComp); },
  903.     categories: [
  904.       { category: "wsm-startup", entry: CATEGORY_COMPONENT_NAME, value: BLOGGER_CONTRACTID },
  905.       { category: "flockWebService", entry: CATEGORY_ENTRY_NAME, value: BLOGGER_CONTRACTID }
  906.     ]
  907.   });
  908. }
  909.  
  910. // ========== END XPCOM Module support ==========
  911.  
  912.  
  913. /* ********** Account Class ********** */
  914.  
  915. function flockBLAccount() {
  916.   this.logger = Cc['@flock.com/logger;1'].createInstance(Ci.flockILogger);
  917.   this.logger.init("bloggerAccount");
  918.  
  919.   this.faves_coop = Cc['@flock.com/singleton;1'].getService(Ci.flockISingleton).getSingleton('chrome://browser/content/flock/common/load-faves-coop.js').wrappedJSObject;
  920.  
  921.   this.acUtils = Cc["@flock.com/account-utils;1"].getService(Ci.flockIAccountUtils);
  922.  
  923.   this.service = Cc[BLOGGER_CONTRACTID].getService(Ci.flockIBlogWebService)
  924. }
  925.  
  926. // nsISupports implementation
  927. flockBLAccount.prototype.QueryInterface = function(iid) {
  928.   if (!iid.equals(Ci.nsISupports) &&
  929.     !iid.equals(Ci.flockIWebServiceAccount) &&
  930.     !iid.equals(Ci.flockIBlogWebServiceAccount))
  931.   {
  932.     throw Components.results.NS_ERROR_NO_INTERFACE;
  933.   }
  934.   return this;
  935. }
  936.  
  937. // flockIWebServiceAccount implementation
  938. flockBLAccount.prototype.login = function(listener) {
  939.   this.logger.info("{flockIWebServiceAccount}.login()");
  940.   if (listener) {
  941.     listener.onSuccess(this, "login");
  942.   }
  943. }
  944. flockBLAccount.prototype.logout = function(listener) {
  945.   this.logger.info("{flockIWebServiceAccount}.logout()");
  946.   var c_acct = this.faves_coop.get(this.urn);
  947.   if (c_acct.isAuthenticated) {
  948.     c_acct.isAuthenticated = false;
  949.     var cookieManager = Components.classes["@mozilla.org/cookiemanager;1"]
  950.                                   .getService(Components.interfaces.nsICookieManager);
  951.     cookieManager.remove(".blogger.com", "B2I", "/", false);
  952.     cookieManager.remove(".blogger.com", "blogger_SID", "/", false);
  953.     cookieManager.remove(".blogger.com", "ServerID", "/", false);
  954.     cookieManager.remove(".blogger.com", "__utma", "/", false);
  955.     cookieManager.remove(".blogger.com", "__utmb", "/", false);
  956.     cookieManager.remove(".blogger.com", "__utmc", "/", false);
  957.     cookieManager.remove(".blogger.com", "__utmz", "/", false);
  958.     cookieManager.remove(".blogger.com", "NSC_cmphhfs-fyu", "/", false);
  959.     cookieManager.remove("blogger.com", "NSC_cmphhfs-fyu", "/", false);
  960.     cookieManager.remove("www.blogger.com", "NSC_cmphhfs-fyu", "/", false);
  961.     cookieManager.remove("www.blogger.com", "JSESSIONID", "/", false);
  962.     cookieManager.remove(".www2.blogger.com", "__utma", "/", false);
  963.     cookieManager.remove(".www2.blogger.com", "__utmb", "/", false);
  964.     cookieManager.remove(".www2.blogger.com", "__utmc", "/", false);
  965.     cookieManager.remove(".www2.blogger.com", "__utmz", "/", false);
  966.     cookieManager.remove("www2.blogger.com", "S", "/", false);
  967.     cookieManager.remove("www.google.com", "LSID", "/accounts", false);
  968.   }
  969.   if (listener) {
  970.     listener.onSuccess(this, "logout");
  971.   }
  972. }
  973. flockBLAccount.prototype.activate = function(aListener) {
  974.   this.logger.info("{flockIWebServiceAccount}.activate()");
  975. }
  976. flockBLAccount.prototype.deactivate = function() {
  977.   this.logger.info("{flockIWebServiceAccount}.deactivate()");
  978. }
  979. flockBLAccount.prototype.keep = function() {
  980.   var c_acct = this.faves_coop.get(this.urn);
  981.   c_acct.isTransient = false;
  982.   this.acUtils.makeTempPasswordPermanent(this.service.urn+':'+c_acct.accountId);
  983. }
  984. flockBLAccount.prototype.remove = function() {
  985.   this.service.removeAccount(this.urn);
  986. }
  987.  
  988. // flockIBlogWebServiceAccount implementation
  989. flockBLAccount.prototype.getBlogs = function() {
  990.   this.logger.info("{flockIBlogWebServiceAccount}.getBlogs()");
  991.   var blogsEnum = {
  992.     QueryInterface : function(iid) {
  993.       if (!iid.equals(Ci.nsISupports) &&
  994.           !iid.equals(Ci.nsISimpleEnumerator))
  995.       {
  996.         throw Components.results.NS_ERROR_NO_INTERFACE;
  997.       }
  998.       return this;
  999.     },
  1000.     hasMoreElements : function() {
  1001.       return false;
  1002.     },
  1003.     getNext : function() {
  1004.     }
  1005.   };
  1006.   return blogsEnum;
  1007. }
  1008.  
  1009.